/**
 * Created by AMD on 31.10.14.
 */
package view {

import ShopObjects.AbstractGameObjectView;

import ShopObjects.DoorView;
import ShopObjects.Shelf1View;

import components.CashDeskComponent;

import components.ShelfComponent;
import components.ShopperComponent;

import dragonBones.animation.WorldClock;

import flash.filters.GlowFilter;

import flash.geom.Matrix;
import flash.geom.Point;

import flash.geom.Point;
import flash.utils.getTimer;

import layers.GameLayer;

import messages.DebugMessage;

import messages.ModelToViewMessage;

import messages.ViewToControllerMessage;
import messages.ViewToViewMessage;

import model.Constants;

import model.objects.CellData;

import model.objects.ProductData;
import model.objects.ShopDesignData;

import model.objects.ShopObjectData;
import model.objects.ShopperData;
import model.prototypes.ShelfProto;
import model.prototypes.ShelfProto;
import model.prototypes.ShopObjectProto;

import mvcexpress.core.CommandMap;

import mvcexpress.core.MediatorMap;

import mvcexpress.mvc.Mediator;

import org.osflash.signals.DeluxeSignal;

import org.osflash.signals.Signal;

import starling.display.Image;
import starling.display.QuadBatch;

import starling.display.Sprite;
import starling.events.EnterFrameEvent;

import starling.events.Event;
import starling.events.Touch;
import starling.events.TouchEvent;
import starling.events.TouchPhase;
import starling.filters.BlurFilter;
import starling.filters.ColorMatrixFilter;

public class GameLayerMediator extends Mediator{
    [Inject]
    public var gameLayer:GameLayer;

    private var _dragDelta:Point = new Point();
    private var _draggingGameLayer:Boolean = false;
    private var _dragInertion:Point = new Point(0,0);

    private var _frameCounter:uint = 0;
    private var _secondsCounter:uint = 0;


    private var _simpleMatrix:Matrix = new Matrix();
    private static var _highlightFilter:BlurFilter = BlurFilter.createGlow(0xffffff,10,0.25,0.5)
    override protected function onRegister():void {
        trace("GameLayerMediator onRegister");
        gameLayer.addEventListener(TouchEvent.TOUCH, this.HANDLER_gameLayerTouch);
        addHandler(ModelToViewMessage.SHOP_DESIGN_UPDATE, this.HANDLER_shopDesignUpdate);
        //addHandler(ModelToViewMessage.SHOP_OBJECT_UPDATE, this.HANDLER_shopObjectUpdate);
        addHandler(ModelToViewMessage.CREATE_SHOP_OBJECT, this.HANDLER_createShopObject);

        addHandler(ModelToViewMessage.SHOP_OBJECTS_RESET, this.HANDLER_shopObjectsReset);
        addHandler(ModelToViewMessage.SHOP_DOOR_STATE_UPDATE, this.HANDLER_doorStateUpdate);

        addHandler(ModelToViewMessage.CONTEXT_MENU_WO_NEW_TARGET, HANDLER_wallObjectHighlight);

        addHandler(ModelToViewMessage.TOGGLE_DRAG_GAME_LAYER,this.HANDLER_toggleDragVariable);


        gameLayer.addEventListener(EnterFrameEvent.ENTER_FRAME, this.HANDLER_enterFrame);

        addHandler(ModelToViewMessage.HIGHLIGHT_QUAD, this.HANDLER_highlightQuad);
        addHandler(ModelToViewMessage.REMOVE_HIGHLIGHT_QUAD, this.HANDLER_removeHighlightQuad);

        addHandler(ViewToViewMessage.REQUEST_Z_SORT, HANDLER_requestZSort);
        addHandler(ViewToViewMessage.REQUEST_UNMEDIATE, HANDLER_requestUnmediate);

        //debug handlers
        addHandler(DebugMessage.VISUALIZE_OCC_POINTS, this.DEBUG_showOCCPoints);
        addHandler(DebugMessage.HIGHLIGHT_QUAD, this.HANDLER_highlightQuad);
    }

    private var _highlightedWallObjectQB:QuadBatch = new QuadBatch();
    private function HANDLER_wallObjectHighlight(params:Object):void {
        if(params == null){
            this._highlightedWallObjectQB.reset();
            this._highlightedWallObjectQB.removeFromParent();
            gameLayer.removeDoorsHighlighting();
        } else {
            this._highlightedWallObjectQB.reset();
            this._bufImage = GraphicFactory.getImageForRender(params.full_sprite_name);
            gameLayer.removeDoorsHighlighting();

            if(params.is_door){
                gameLayer.highlightDoorOnQuad(params.quad);
            } else {
                if(Point(params.quad).y == -1){
                    this._highlightedWallObjectQB.transformationMatrix = ShopView.matrix_wall1;
                    this._bufImage.x = Point(params.quad).x*100*Math.cos(Math.PI/4);
                } else if(Point(params.quad).x == -1){
                    this._highlightedWallObjectQB.transformationMatrix = ShopView.matrix_wall2;
                    this._bufImage.x = -71 - Point(params.quad).y*100*Math.cos(Math.PI/4);
                }
                //this._highlightedWallObjectQB.y += 100;
                this._highlightedWallObjectQB.addImage(this._bufImage);
                this._highlightedWallObjectQB.filter = _highlightFilter;
                gameLayer.shopView.addChild(this._highlightedWallObjectQB);
            }
        }
    }

    private var _shopDesignDataCached:ShopDesignData = null;
    private function HANDLER_shopDesignUpdate(data:Object):void {
        switch (data.type){
            case Constants.SHOP_DESIGN_FULL_UPDATE:
                this._shopDesignDataCached = data.param as ShopDesignData;
                var d:ShopDesignData = this._shopDesignDataCached;
                gameLayer.shopView.updateAsQuad(d.floorData,d.wallMaskX,d.wallMaskY,d.wallCoverDataX,d.wallCoverDataY);
                this._updateDoors(d.doorDataX, d.doorDataY);
                break;
            case ShopDesignData.SIGNAL_UPDATE_FLOOR:
                gameLayer.shopView.updateFloorQuadAt(data.param.quad as Point,data.param.floor_sprite as String);
                break;
            case ShopDesignData.SIGNAL_UPDATE_WALL:
            case ShopDesignData.SIGNAL_UPDATE_WALL_COVER:
            case ShopDesignData.SIGNAL_UPDATE_WALL_MASK:
                gameLayer.shopView.updateWallQuadSide(data.param.side,data.param.wall_data as Vector.<String>,data.param.wall_cover_data as Vector.<String>);
                break;
            case ShopDesignData.SIGNAL_UPDATE_DOORS:
                this._updateDoors(data.param.door_data_x, data.param.door_data_y);
                break;
        }
    }


    private function _updateDoors(doorDataX:Vector.<String>, doorDataY:Vector.<String>):void {
        var i:int;
        var _bufDoor:DoorView;
        var _bufCoords:Point;
        gameLayer.removeAllDoors();

        for (i = 0; i< doorDataX.length; i++){
            if(doorDataX[i] != null){
                _bufDoor = new DoorView(doorDataX[i]);
                _bufDoor.angle = 225;
                _bufCoords = gameLayer.getLocalCoordsByQuadrant(new Point(i,0));
                _bufDoor.x = _bufCoords.x;
                _bufDoor.y = _bufCoords.y;
                gameLayer.addDoor(_bufDoor);
            }
        }
        for (i = 0; i< doorDataY.length; i++){
            if(doorDataY[i] != null){
                _bufDoor = new DoorView(doorDataY[i]);
                _bufDoor.angle = 135;
                _bufCoords = gameLayer.getLocalCoordsByQuadrant(new Point(0,i));
                _bufDoor.x = _bufCoords.x;
                _bufDoor.y = _bufCoords.y;
                gameLayer.addDoor(_bufDoor);
            }
        }
    }
    private function HANDLER_doorStateUpdate(param:Object):void {
        gameLayer.setDoorState(param.position as Point, param.opened);
    }

    private function HANDLER_shopObjectsReset(blankParam:Object):void {
        gameLayer.removeAllSortableObjects();
        
    }

//    private function HANDLER_shopObjectUpdate(shopObjectData:ShopObjectData):void {
//       // this.updateObject(shopObjectData.proto,shopObjectData.position,shopObjectData.angle,shopObjectData.params)
//    }


    public function HANDLER_createShopObject(shopObjectData:ShopObjectData):void {

        switch (shopObjectData.proto.type){
            case Constants.TYPE_SHELF: // shelf
                mediatorMap.mediate(new ShelfComponent(gameLayer,shopObjectData));
                break;
            case Constants.TYPE_CASH_DESK: // Cash Desk
                mediatorMap.mediate(new CashDeskComponent(gameLayer,shopObjectData));
                break;
            case Constants.TYPE_SHOPPER:
                mediatorMap.mediate(new ShopperComponent(gameLayer,shopObjectData as ShopperData));
                break;
        }

        gameLayer.sortObjectsZOrder();
    }
    public function HANDLER_requestUnmediate(params:Object):void {
        mediatorMap.unmediate(params.object);

        gameLayer.sortObjectsZOrder();
    }

    ///param: {object: <ShopObject>, quad: <Point>}
    private function HANDLER_requestZSort(param:Object):void {
        gameLayer.sortObjectsZOrder();
    }



    override protected function onRemove():void {

    }

    private var _bufTouch:Touch = null;
    private var _bufTouchPoint:Point = new Point();
    private var _mouseQuadrantOld:Point = new Point();
    private var _mouseQuadrant:Point = new Point();
    private function HANDLER_gameLayerTouch(event:TouchEvent):void {
        this._bufTouch = event.touches[0];

        if(this._bufTouch == null) return; //for safety

        this._bufTouchPoint.setTo(this._bufTouch.globalX,this._bufTouch.globalY);

        //this._mouseQuadrantOld.setTo(this._mouseQuadrant.x,this._mouseQuadrant.y);
        this._mouseQuadrantOld = this._mouseQuadrant.clone();
        //gameLayer.shopView.getQuadrantToPoint(this._bufTouchPoint, this._mouseQuadrant);
        this._mouseQuadrant = gameLayer.shopView.getQuadrant(this._bufTouchPoint);


        if(this._bufTouch.phase != TouchPhase.HOVER && this._bufTouch.phase != TouchPhase.MOVED){
            sendMessage(ViewToControllerMessage.GAME_LAYER_TOUCH,{touch:this._bufTouch, quad:this._mouseQuadrant})
        } else if(this._bufTouch.phase == TouchPhase.HOVER && (this._mouseQuadrant.equals(this._mouseQuadrantOld) == false)){
            sendMessage(DebugMessage.HIGHLIGHT_QUAD,{position:_mouseQuadrant, color:0x00ff00, id:"mouse"});
            sendMessage(ViewToControllerMessage.GAME_LAYER_TOUCH,{touch:this._bufTouch, quad:this._mouseQuadrant, quad_old:this._mouseQuadrantOld})
        }

        if(this._bufTouch.phase == TouchPhase.MOVED){
            if(this._draggingGameLayer){
                this.gameLayer.x = this._bufTouch.globalX + this._dragDelta.x;
                this.gameLayer.y = this._bufTouch.globalY + this._dragDelta.y;
            }
        }
    }
    private function HANDLER_toggleDragVariable(param:Object):void {
        if(param.drag){//start drag
            this._dragDelta = new Point(gameLayer.x,gameLayer.y).subtract(Point(param.point));
        } else {//stop drag
            this._dragInertion = param.inertion;
        }
        this._draggingGameLayer = Boolean(param.drag);
    }
    public function HANDLER_enterFrame(event:EnterFrameEvent):void {

        WorldClock.clock.advanceTime(-1);
        this._frameCounter ++;
        if(this._frameCounter >= 60){
            this._frameCounter = 0;
            this._secondsCounter ++;
            sendMessage(ViewToControllerMessage.ONE_SECOND_TIMER_FROM_MEDIATOR);
        }

        if(!this._draggingGameLayer){
            if(Math.abs(this._dragInertion.x) > 1 || Math.abs(this._dragInertion.y) > 1 ){
                this.gameLayer.x += this._dragInertion.x *0.2;
                this.gameLayer.y += this._dragInertion.y *0.2;

                this._dragInertion.x *= 0.84;
                this._dragInertion.y *= 0.84;
            } else {
                this._dragInertion.x = this._dragInertion.y = 0;
            }

        }

    }

    private var _bufImage:Image;
    private var _isoMatrix:Matrix = null;
    private var _debug_occ_points:Vector.<Image> = new Vector.<Image>();
    private var _bufPoint:Point;
    private function DEBUG_showOCCPoints(gameField:Object):void {
        var occ_vec:Vector.<CellData> = new Vector.<CellData>();
        for (var name:String in gameField){
            occ_vec.push(gameField[name] as CellData);
        }
        var i:int = 0;
        for(i = 0;i<_debug_occ_points.length;i++){
            _debug_occ_points[i].parent.removeChild(_debug_occ_points[i]);
        }
        _debug_occ_points = new Vector.<Image>();

        for(i = 0;i< occ_vec.length; i++){
            _bufImage = _getHighlightQuad();
            _bufPoint = this.gameLayer.getLocalCoordsByQuadrant(occ_vec[i].quadCoords);

            switch (occ_vec[i].occ_var){
                case 1:
                    _bufImage.color = 0xff0000;
                    break;
                case 0:
                    _bufImage.color = 0x00ff00;
                    break;
                default:
                    _bufImage.color = 0x0000ff;
                    break;
            }


            _bufImage.x = _bufPoint.x;
            _bufImage.y = _bufPoint.y;
            _bufImage.alpha = 0.2;
            this.gameLayer.addChild(_bufImage);
            _debug_occ_points.push(_bufImage);
        }

    }

    private var _hightlightsById:Object = {};
    ///position:Point,color:uint = 0x557788, id:String = null
    private function HANDLER_highlightQuad(data:Object):void {

        var position:Point = data.position;
        var color:uint = data.color?data.color:0x00ff00;
        var id:String = data.id?data.id:null;

        if(id != null){
            this._bufImage = this._hightlightsById[id];
            if(this._bufImage == null){
                this._bufImage = this._getHighlightQuad();
                this._hightlightsById[id] = this._bufImage;
            }
        } else {
            this._bufImage = this._getHighlightQuad();
        }
        this._bufPoint = this.gameLayer.getLocalCoordsByQuadrant(position);

        this._bufImage.x = _bufPoint.x;
        this._bufImage.y = _bufPoint.y;

        this._bufImage.color = color;

        if(data.alpha != null){
            this._bufImage.alpha = data.alpha;
        }
        this.gameLayer.addChild(_bufImage);
    }

    private function _getHighlightQuad():Image {
        if(this._isoMatrix == null){
            this._isoMatrix = new Matrix();
            this._isoMatrix.rotate(Math.PI/4);
            this._isoMatrix.scale(1,0.5);
        }

        this._bufImage = GraphicFactory.getImageByName("ShopItems/Floors/Floor1");
        this._bufImage.transformationMatrix = this._isoMatrix;
        this._bufImage.alignPivot();
        this._bufImage.color = 0x00ff00;
        this._bufImage.alpha = 0.2;
        this._bufImage.touchable = false;
        return _bufImage;
    }

    public function HANDLER_removeHighlightQuad(data:Object):void {
        if(this._hightlightsById[data.id] != null){
            (this._hightlightsById[data.id] as Image).removeFromParent();
        }
    }


}
}
